package mc2;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

import mc2.ui.*;

public class Channel{
    private String _name;
    private String _key;
    private User _owner;
    private FrmChan _ui;
    
    private final List<User> _users= new CopyOnWriteArrayList<User>();
    private static TreeMap _knownchannels=new TreeMap();
    
    private final static long USER_ACTIVITY_TIMEOUT = 5 * 60 * 1000;
    
    public static Channel GetByName(String iName){
        if(_knownchannels.containsKey(iName))
            return (Channel)_knownchannels.get(iName);
        else
            return null;
    }
    
    public String GetName(){
        return _name;
    }
    
    public User GetOwner(){
        return _owner;
    }
    
    public void SetOwner(User iOwner){
        _owner=iOwner;
    }
    
    public User[] GetUsers(){
        User[] outArr=new User[_users.size()];
        
        _users.toArray(outArr);
        return outArr;
    }
    
        
    public void AddUser(User iUser){
        
        if(_users.contains(iUser))
           return;
        
        _users.add(iUser);
        _ui.UpdateNickList(GetUsers());
        
    }
    
    public void Join(User iUser){
        Notice(iUser.GetName() + " joined " + GetName());
        AddUser(iUser);
        _ui.handleReceiveEvent(iUser.GetName());
        
    }
   
    public void Notice(String iStr){
        _ui.AddRecvLine("::: "+iStr);
    }
    
    public void Part(User iUser, boolean dead){
        if(_users.contains(iUser))
            _users.remove(iUser);
        
        String leftOrDead = dead ? "dead" : "left";
        Notice(iUser.GetName() + " " + leftOrDead + " " + GetName());
        _ui.UpdateNickList(GetUsers());
        _ui.handleReceiveEvent(iUser.GetName());
    }
    
    
    public void MessageReceived(ChannelMessage iMsg){
         String timStamp = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new Date());
         _ui.AddRecvLine("< "+iMsg.GetSender().GetName() + "@"+timStamp+"> " + iMsg.GetText());
         _ui.handleReceiveEvent(iMsg.GetSender().GetName());
    }
    
    public void SetKey(String iKey){
        _key=iKey;
        Manager.GetInstance().GetDispatcher().SetKey(iKey);
    }
    
    /** Creates a new instance of Channel */
    public Channel(String iName) {
        _name=iName;
       
        _ui=new FrmChan();
        _ui.setTitle(Manager.GetInstance().GetMe() +  "@" + _name);
        _ui.pack();
        _ui.setVisible(true);
        
        _knownchannels.put(_name,this);
        
        new Thread() {
          
          public void run() {
            while(true) {
              try {
                Thread.sleep(2000);
                cleanInactiveUsers();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          };
        }.start();
    }
    
    private void cleanInactiveUsers() {
      List<User> copy = new ArrayList<User>();
      copy.addAll(_users);
      
      for(User savedUser : copy) {
        if((System.currentTimeMillis() - savedUser.getLastActivity()) > USER_ACTIVITY_TIMEOUT) {
          Part(savedUser, true);
        }
      }
    }
    
    public void finalize() throws Throwable{
        _knownchannels.remove(this);
        super.finalize();
    }
    
    public boolean equals(Channel iTo){
        if(iTo==null) return false;
        return _name.equals(iTo._name);
    }
    
    
   public void updateLastActivity(User user) {
     List<User> copy = new ArrayList<User>();
     copy.addAll(_users);
     
     for(User savedUser : copy) {
       if(savedUser.equals(user)) {
         savedUser.setLastActivity(System.currentTimeMillis());
       }
     }
   } 
    
    public static void CreateNew(String iName,String iKey){
        Channel newChan=new Channel(iName);
      if(iKey!=null && iKey.length()>0)
        newChan.SetKey(iKey);
      newChan.SetOwner(Manager.GetInstance().GetMe());
      Manager.GetInstance().SetAndAdvertiseChannel(newChan);
    }
    
    public static void JoinExisting(String iName,String iKey) throws Exception{
        Manager.GetInstance().GetDispatcher().SetKey(iKey);
        ServiceMessage newMsg=new ServiceMessage(Manager.GetInstance().GetMe(),ServiceMessage.CODE_JOIN,iName);
        Manager.GetInstance().GetDispatcher().DispatchToAll(newMsg);
    }
}
